//将所有中间件合成为一个函数

function compose(middleware) {
    //参数一定要是一个数组
    if (!Array.isArray(middleware)) {
        throw new TypeError('Middleware stack must be an array');
    }
    //每一个中间件都必须是一个方法，说明 koa 的 use 方法只负责收储中间件
    for (let fn of middleware) {
        if (typeof fn !== 'function') {
            throw new TypeError('Middleware must be composed of functions!');
        }
    }

    return function(context, next){
        //从数组第一个中间件开始执行
        return dispatch(0);
        function dispatch(i){
            //取出需要执行的中间件
            let fn = middleware[i];
            //已经执行完毕
            if(i===middleware.length){
                // compose 传进来的next，进行收尾工作的，比如返回 404，koa-compose 本身并没有传递任何函数
                fn = next;
            }
            //如果 fn 没有值， 也就是 compose 没有next 参数 
            if(!fn){
                return Promise.resolve();
            }

            try{
                // dispatch 内部没有 this，所以传递了 null
                return Promise.resolve(fn(context, dispatch.bind(null, i+1)));
            }catch(err){
                // 一个出错，程序不会崩溃，但是不会继续执行下去
                return Promise.reject(err);
            }
        }
    }
}

module.exports = compose;